package com.unitd.base.frame.plugins.module.provider.impl;

import com.github.pagehelper.PageInfo;
import com.unitd.base.frame.plugins.module.provider.IBaseProvider;
import com.unitd.base.frame.plugins.module.service.IBaseService;
import com.unitd.base.frame.utils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * IBaseProvider 的实现类,其他的自定义 ProviderImpl,继承自它,可以获得常用的dubbo服务的增删查改操作,未实现的方法由子类各自实现
 * @param <Model> 代表实际业务操作中的数据对象
 * @param <PK> 对象的主键类型
 * @filename BaseProviderImpl.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2019-01-23
 */
public abstract class BaseProviderImpl<VO, Model, PK> implements IBaseProvider<VO, Model, PK> {

	/**
	 * 定义成抽象方法,由子类实现,完成service的注入
	 * @return GenericDao实现类
	 */
	protected abstract IBaseService<Model, PK> getService();

	/**
	 * 保存(持久化)对象(完全保存)
	 * @param clazz 要持久化的对象
	 */
	@Override
	public int insert(VO vo, Class<Model> clazz) {
		try {
			Model entity = clazz.newInstance();
			// 将数据传输对象数据copy到数据库对象上
			PropertyUtils.copyProperties(entity, vo);

			// 保存持久化的对象数据到数据库中
			return getService().insert(entity);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 保存(持久化)对象(非空字段保存, 空字段按照默认值)
	 * @param vo 数据传输对象
	 * @param clazz 要持久化的对象
	 */
	@Override
	public int insertSelective(VO vo, Class<Model> clazz) {
		try {
			Model entity = clazz.newInstance();
			// 将数据传输对象数据copy到数据库对象上
			PropertyUtils.copyProperties(entity, vo);

			// 保存持久化的对象数据到数据库中
			return getService().insertSelective(entity);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 批量保存(持久化)对象(完全保存)
	 * @param vos 数据传输对象
	 * @param clazz 要持久化的对象
	 */
	@Override
	public int batchInsert(List<VO> vos, Class<Model> clazz) {
		try {
			Model entity;

			int result = 0;
			for(VO vo : vos) {
				entity = clazz.newInstance();

				// 将数据传输对象数据copy到数据库对象上
				PropertyUtils.copyProperties(entity, vo);

				// 保存持久化的对象数据到数据库中
				result += getService().insertSelective(entity);
			}
			return result;
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 批量保存(持久化)对象(非空字段保存,空字段按照默认值)
	 * @param vos 数据传输对象
	 * @param clazz 要持久化的对象
	 */
	@Override
	public int batchInsertSelective(List<VO> vos, Class<Model> clazz) {
		try {
			Model entity;

			int result = 0;
			for(VO vo : vos) {
				entity = clazz.newInstance();

				// 将数据传输对象数据copy到数据库对象上
				PropertyUtils.copyProperties(entity, vo);

				// 保存持久化的对象数据到数据库中
				result += getService().insertSelective(entity);
			}
			return result;
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 根据指定的唯一标识符删除持久化对象
	 * @param id 指定的唯一标识符
	 */
	@Override
	public int deleteByPrimaryKey(PK id) {
		return getService().deleteByPrimaryKey(id);
	}

	/**
	 * 更新(持久化)对象
	 * @param vo 数据传输对象
	 * @param clazz (持久化)对象
	 */
	@Override
	public int  updateByPrimaryKey(VO vo, Class<Model> clazz) {
		try {
			Model entity = clazz.newInstance();
			// 将数据传输对象数据copy到数据库对象上
			PropertyUtils.copyProperties(entity, vo);

			// 更新持久化对象
			return getService().updateByPrimaryKey(entity);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 更新(持久化)对象
	 * @param vo 数据传输对象
	 * @param clazz (持久化)对象
	 */
	@Override
	public int updateByPrimaryKeySelective(VO vo, Class<Model> clazz) {
		try {
			Model entity = clazz.newInstance();
			// 将数据传输对象数据copy到数据库对象上
			PropertyUtils.copyProperties(entity, vo);

			// 更新持久化对象
			return getService().updateByPrimaryKeySelective(entity);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 获取指定的唯一标识符对应的持久化对象
	 * @param clazz 数据传输对象
	 * @param id 指定的唯一标识符
	 * @return 指定的唯一标识符对应的持久化对象，如果没有对应的持久化对象，则返回null。
	 */
	@Override
	public VO getByKey(Class<VO> clazz, PK id) {
		try {
			VO vo = clazz.newInstance();
			Model entity= getService().selectByPrimaryKey(id);
			if(!BeanUtils.isNull(entity)) {
				// 将查询到的持久化数据对象copy到数据传输对象上
				PropertyUtils.copyProperties(vo, entity);
				return vo;
			}
			return null;
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 获取指定条件对应的持久化对象
	 * @param vo 查询条件
	 * @param voClazz 前端需要展示的数据对象类
	 * @param clazz 持久化数据对象类
	 * @return 指定持久对象的所有 记录,如果没有对应的持久化对象，则返回null。
	 */
	@Override
	public VO getByBean(VO vo, Class<VO> voClazz, Class<Model> clazz) {
		try {
			Model model = clazz.newInstance();
			PropertyUtils.copyProperties(model, vo);

			// 调用持久化查询,根据条件获取持久化对象列表
			model = getService().selectByBean(model);

			// copy数据到vo
			return copyModels2Vo(model, voClazz);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 根据指定查询条件,获取对应的记录列表
	 * @param vo 查询条件
	 * @param voClazz 前端需要展示的数据对象类
	 * @param clazz 持久化数据对象类
	 * @return 指定持久对象的所有 记录,如果没有对应的持久化对象，则返回null。
	 */
	@Override
	public List<VO> listByBean(VO vo, Class<VO> voClazz, Class<Model> clazz) {
		try {
			Model model = clazz.newInstance();
			PropertyUtils.copyProperties(model, vo);

			// 调用持久化查询,根据条件获取持久化对象列表
			List<Model> models = getService().listByBean(model);

			// copy数据到vo
			return copyModels2Vos(models, voClazz);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}


	/**
	 * 获取所有记录
	 * @return 指定持久对象的所有 记录,如果没有对应的持久化对象，则返回null。
	 */
	@Override
	public List<VO> listAll(Class<VO> clazz) {
		try {
			List<Model> models = getService().listAll();

			// copy数据到vo
			return copyModels2Vos(models, clazz);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 查询分页数据
	 * @param pageNo 当前页数
	 * @param pageSize 每页记录数
	 * @param clazz 需要转换成的数据类型
	 * @return 分页对象
	 */
	@Override
	public PageInfo<VO> getPageData(int pageNo, int pageSize, Class<VO> clazz) {
		try {
			PageInfo<Model> modelPage =  getService().getPageData(pageNo, pageSize);

			// copy数据到vo
			return copyModels2Vos(modelPage, clazz);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 查询分页数据
	 * @param pageNo 当前页数
	 * @param pageSize 每页记录数
	 * @param clazz 需要转换成的数据类型
	 * @param model 查询条件
	 * @return PageInfo
	 */
	@Override
	public PageInfo<VO> getPageData(int pageNo, int pageSize, Class<VO> clazz, Model model) {
		try {
			PageInfo<Model> modelPage =  getService().getPageData(pageNo, pageSize, model);

			// copy数据到vo
			return copyModels2Vos(modelPage, clazz);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 处理将通过service查询到的持久化数据进行处理后变成需要的VO的数据
	 * @param models 持久化的数据对象列表
	 * @param clazz 需要转换成的VO对象
	 * @return List
	 */
	private List<VO> copyModels2Vos (List<Model> models, Class<VO> clazz) {
		try {
			// 将查询出来的持久化对象转换成数据传输对象VO
			if(!BeanUtils.isNull(models)) {
				List<VO> vos = new ArrayList<>();
				for(Model result : models) {
					vos.add(copyModels2Vo(result, clazz));
				}
				return vos;
			}
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
		return null;
	}

	/**
	 * 处理将通过service查询到的分页持久化数据进行处理后变成需要的VO的分页数据
	 * @param modelPage 持久化的分页数据对象
	 * @param clazz 需要转换成的VO对象
	 * @return 分页对象
	 */
	private PageInfo<VO> copyModels2Vos(PageInfo<Model> modelPage, Class<VO> clazz) {
		try {
			if(!BeanUtils.isNull(modelPage)) {
				PageInfo<VO> voPages = new PageInfo<>();

				// 先将最外层对象进行copy
				PropertyUtils.copyProperties(voPages, modelPage);

				// 将里层的List集合进行属性值的copy
				List<VO> vos = new ArrayList<>();
				for(Model result : modelPage.getList()) {
					VO vo = clazz.newInstance();
					// 将查询到的持久化数据对象copy到数据传输对象上
					PropertyUtils.copyProperties(vo, result);
					vos.add(vo);
				}

				voPages.setList(vos);
				return voPages;
			}
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
		return null;
	}

	/**
	 * 处理将通过service查询到的持久化数据进行处理后变成需要的VO的数据
	 * @param model 持久化的数据对象
	 * @param clazz 需要转换成的VO对象
	 * @return List
	 */
	private VO copyModels2Vo(Model model, Class<VO> clazz) {
		try {
			// 将查询出来的持久化对象转换成数据传输对象VO
			if (!BeanUtils.isNull(model)) {
				VO vo = clazz.newInstance();
				// 将查询到的持久化数据对象copy到数据传输对象上
				PropertyUtils.copyProperties(vo, model);

				return vo;
			}
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
		return null;
	}
}